#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <unix_sock.h>
#include <log_utils.h>
#include <pthread.h>
#include <shmem.h>
#include "list.h"
#include "cJSON.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>



#define MODULE_UNIX "unixs_modbus"
#define N 64

//静态和全局变量
int flag = 0;
static struct unix_param unix_para;
static struct shm_param para;
unsigned char send_control_buf[128] = {0xcc, 0xcc, 0x00, 0x00, 0x00, 0x17, 0x01, 0x10, 0x00, 0x00, 0x00, 0x08, 0x10}; //使用06H功能码进行单寄存器写操作
unsigned char data_modbus[128] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
unsigned char data_recv[128] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; //让控制进程拿到采集的数据
char success_command[128] = "{\"type\": 2,\"result\": 0,\"msg\":\"控制成功\"}";
char failed_command[128] = "{\"type\": 2,\"result\": 1,\"msg\":\"控制失败\"}";

//数据联合体
union val_t
{
    int val_i;
    float val_f;
    int val_b;
};

//创建结构体保存Modbus的IP和端口号
struct mb_info
{
    char ip[32];
    int port;
};

//创建数据采集信息结构体
struct std_node
{
    int key;
    int type;
    int dev_type;        //设备类型
    union val_t old_val; //变化上报后需要更新旧值
    union val_t new_val; //从共享内存取出最新数据，放到new_val中
    int ret;         //默认为-1，采集成功后设置为0，采集失败再置-1
};

struct mb_olddata
{
    float val_101;
    float val_102;
    int val_103;
    float val_104;
    int val_105;
};

//创建采集数据结构体，该结构体保存采集到的最新数据
struct mb_olddata old_data;
struct mb_info mb_infomation;

//解析点表数据保存到内核链表中
struct mb_node
{
    int key;
    char name[128];
    int type;
    int addr;
};

struct mb_node_list
{
    struct mb_node node;
    struct list_head list;
};

//小端转大端
int smalltobig(int le)
{
    return (le & 0xff) << 8 | (le & 0xff00) >> 8;
}

//线程函数1  ----数据采集
void *thread1(void *arg)
{
    int ret = -1;

    //初始化共享内存
    ret = shm_init(&para, "shm_test", sizeof(struct std_node) * 11);
    if (ret < 0)
    {
        return -1;
    }

    //循环连接TCP
    while (1)
    {
        // 0定义变量
        int sockfd;
        int addrlen = sizeof(struct sockaddr);
        struct sockaddr_in serveraddr;

        // 创建一个套接字--socket
        sockfd = socket(AF_INET, SOCK_STREAM, 0);
        if (sockfd < 0)
        {
            perror("socket err");
            exit(-1);
        }

        // 指定服务器地址--sockaddr_in
        bzero(&serveraddr, addrlen);
        serveraddr.sin_family = AF_INET;
        serveraddr.sin_addr.s_addr = inet_addr(mb_infomation.ip);
        serveraddr.sin_port = htons(mb_infomation.port);

        // 3连接服务器--connect
        if (connect(sockfd, (struct sockaddr *)&serveraddr, addrlen) < 0)
        {
            perror("connect err");
            exit(-1);
        }

        //发送命令缓冲区
        unsigned char send_buf[128] = {0xdd, 0xdd, 0x00, 0x00, 0x00, 0x06, 0x01, 0x03, 0x00, 0x00, 0x00, 0x08};

        //接收缓冲区
        unsigned char recv_buf[128] = {0};

        while (1)
        {
            if (flag == 1)
            {
                flag = 0;
                break;
            }
            send(sockfd, send_buf, 12, 0);
            int ret = recv(sockfd, recv_buf, 128, 0);
            if (ret < 0)
            {
                perror("recv err");
                continue;
            }

            int i;
            printf("采集数据的接收码:");
            for (i = 0; i < ret; i++)
            {
                //将接收的内容打印出来看看
                printf("%02x ", recv_buf[i]);
            }
            printf("\n");

            //解析出需要的数据来
            float *p = recv_buf + 9; //将指针偏移到数据位置
            short *q = p;

#if 0 //因为接收的数据是按照大端ABCD存储的，而我们的CPU是小端模式，所以要将字节序置换     
            float data;
            conver_endian_long(&data, p, 4);
#else //如果接收数据格式是DCBCA（小端）存储，那么就简单了，直接定义一个float类型指针变量，指向这四个字节即可取出值来
            float data = *p;
            short data_b;
            p++;
#endif
            struct std_node *data_array;
            data_array = shm_getaddr(&para);
            printf("===================采集线程1=================\n");
            for (i = 0; i < 5; i++)
            {
                data_array[i].old_val = data_array[i].new_val;
            }

            printf("温度 = %.2f\n", data);
            //将获取的数据封装成结构体放到共享内存中
            data_modbus[0] = data;
            data_array[0].key = 101;
            data_array[0].dev_type = 1;
            data_array[0].new_val.val_f = data;
            data_array[0].type = 3; //浮点类型
            old_data.val_101 = data;
            data = *p;
            p++;

            printf("湿度 = %.2f\n", data);
            data_modbus[0] = data;
            data_array[1].key = 102;
            data_array[1].dev_type = 1;
            data_array[1].new_val.val_f = data;
            data_array[1].type = 3;
            old_data.val_102 = data;
            q = p;
            data_b = *q++;

            printf("空调开关 = %d\n", smalltobig(data_b));
            data_modbus[0] = data;
            data_array[2].key = 103;
            data_array[2].dev_type = 1;
            data_array[2].new_val.val_b = smalltobig(data_b);
            data_array[2].type = 1;
            old_data.val_103 = data_b;
            p = q;
            data = *p++;

            printf("空调温度 = %.2f\n", data);
            data_modbus[0] = data;
            data_array[3].key = 104;
            data_array[3].dev_type = 1;
            data_array[3].new_val.val_f = data;
            data_array[3].type = 3;
            old_data.val_104 = data;
            q = p;
            data_b = *q;

            printf("灯控 = %d\n", smalltobig(data_b));
            data_modbus[0] = data;
            data_array[4].key = 105;
            data_array[4].dev_type = 1;
            data_array[4].new_val.val_b = smalltobig(data_b);
            data_array[4].type = 1;
            old_data.val_105 = data_b;
            sleep(1);
        }
        // 5关闭连接--close
        close(sockfd);
    }
}

//线程函数2  ----控制指令
void *thread2(void *arg)
{
    while (1)
    {
        char data[256] = {0};
        
        //线程开启UNIX接受上报进程的控制指令
        unix_init_server(&unix_para, MODULE_UNIX);

        printf("unix 配置成功\n");
        while (1)
        {
            printf("===================控制线程2=================\n");
            bzero(data, 256);
            if (unix_server_recv(&unix_para, data, 256) > 0)
            {
                flag = 1;
                sleep(1);
                int sockfd;
                int addrlen = sizeof(struct sockaddr);
                struct sockaddr_in serveraddr;

                // 1创建一个套接字--socket
                sockfd = socket(AF_INET, SOCK_STREAM, 0);
                if (sockfd < 0)
                {
                    perror("socket err");
                    exit(-1);
                }

                // 2指定服务器地址--sockaddr_in
                bzero(&serveraddr, addrlen);
                serveraddr.sin_family = AF_INET;
                serveraddr.sin_addr.s_addr = inet_addr(mb_infomation.ip);
                serveraddr.sin_port = htons(mb_infomation.port);

                // 3连接服务器--connect
                if (connect(sockfd, (struct sockaddr *)&serveraddr, addrlen) < 0)
                {
                    perror("connect err");
                    exit(-1);
                }

                //线程开启UNIX接受上报进程的控制指令
                unix_init_server(&unix_para, MODULE_UNIX);
                cJSON *root = NULL;
                int j;
                cJSON *item = NULL;
                cJSON *value_json = NULL;
                cJSON *key_json = NULL;
                root = cJSON_Parse(data);
                if (!root)
                {
                    printf("Error control from thread!\n");
                }
                else
                {
                    //解析上报进程发过来的json
                    item = cJSON_GetObjectItem(root, "data");
                    key_json = cJSON_GetObjectItem(item, "key");
                    value_json = cJSON_GetObjectItem(item, "val");
                    printf("val:->%s\n", value_json->valuestring);
                    printf("key:->%d\n", key_json->valueint);
                    printf("\n");
                    int num = key_json->valueint;
                    float *ptr_float = send_control_buf + 13;
                    short *ptr_short = NULL;

                    //将功能码的数据位线填入之前的数值
                    *ptr_float = old_data.val_101;
                    ptr_float = send_control_buf + 17;
                    *ptr_float = old_data.val_102;
                    ptr_short = send_control_buf + 21;
                    *ptr_short = old_data.val_103;
                    ptr_float = send_control_buf + 23;
                    *ptr_float = old_data.val_104;
                    ptr_short = send_control_buf + 27;
                    *ptr_short = old_data.val_105;
                    for (j = 0; j < 30; j++)
                    {
                        printf("%x ", send_control_buf[j]);
                    }
                    printf("\n");
                    //根据Key判断修改操作码 发送给Modbus
                    switch (num)
                    {
                        case 101:
                        {
                            double val;
                            val = atof(value_json->valuestring);
                            printf("测试2222：%f\n", val);
                            float *temp = send_control_buf + 13;
                            *temp = val;
                            break;
                        }
                        case 102:
                        {
                            double val;
                            val = atof(value_json->valuestring);
                            printf("测试2222：%f\n", val);
                            float *temp = send_control_buf + 17;
                            *temp = val;
                            break;
                        }
                        case 103:
                        {
                            int val = value_json->valueint;
                            short *temp = send_control_buf + 21;
                            *temp = smalltobig(val);
                            break;
                        }
                        case 104:
                        {
                            double val;
                            val = atof(value_json->valuestring);
                            printf("测试2222：%f\n", val);
                            float *temp = send_control_buf + 23;
                            *temp = val;
                            break;
                        }
                        case 105:
                        {
                            int val = value_json->valueint;
                            short *temp = send_control_buf + 27;
                            *temp = smalltobig(val);
                            break;
                        }
                    }
                    //打印发送给Modbus的操作码
                    printf("发给Modbus的控制码：");
                    for (j = 0; j < 30; j++)
                    {
                        printf("%x ", send_control_buf[j]);
                    }
                    printf("\n");
                    send(sockfd, send_control_buf, 30, 0);
                    printf("控制发送指令成功\n");
                    sleep(1);
                    //判断是否成功,并发送结果给上报进程
                    switch (num)
                    {
                        case 101:
                        {
                            if ((old_data.val_101 - atof(value_json->valuestring)) < 0.1)
                            {
                                unix_server_send(&unix_para, success_command, sizeof(success_command));
                                printf("控制101成功！\n");
                            }
                            else
                            {
                                unix_server_send(&unix_para, failed_command, sizeof(failed_command));
                                printf("控制101失败！\n");
                            }
                            break;
                        }
                        case 102:
                        {
                            if ((old_data.val_102 - atof(value_json->valuestring)) < 0.1)
                            {
                                unix_server_send(&unix_para, success_command, sizeof(success_command));
                                printf("控制102成功！\n");
                            }
                            else
                            {
                                unix_server_send(&unix_para, failed_command, sizeof(failed_command));
                                printf("old_data:%f\n", old_data.val_102);
                                printf("value:%f\n", atof(value_json->valuestring));
                                printf("控制102失败！\n");
                            }
                            break;
                        }
                        case 103:
                        {
                            if (old_data.val_103 == value_json->valueint)
                            {
                                unix_server_send(&unix_para, success_command, sizeof(success_command));
                                printf("控制103成功！\n");
                            }
                            else
                            {
                                unix_server_send(&unix_para, failed_command, sizeof(failed_command));
                                printf("控制103失败！\n");
                            }
                            break;
                        }
                        case 104:
                        {
                            if ((old_data.val_104 - atof(value_json->valuestring)) < 0.1)
                            {
                                unix_server_send(&unix_para, success_command, sizeof(success_command));
                                printf("控制104成功！\n");
                            }
                            else
                            {
                                unix_server_send(&unix_para, failed_command, sizeof(failed_command));
                                printf("控制104失败！\n");
                            }
                            break;
                        }
                        case 105:
                        {
                            if (old_data.val_105 == value_json->valueint)
                            {
                                unix_server_send(&unix_para, success_command, sizeof(success_command));
                                printf("控制105成功！\n");
                            }
                            else
                            {
                                unix_server_send(&unix_para, failed_command, sizeof(failed_command));
                                printf("控制104失败！\n");
                            }
                            break;
                        }
                    }
                }
                close(sockfd);
            }
            sleep(1);
        }
    }
}

//大小端转换函数
int conver_endian_long(unsigned char *dst, const unsigned char *src, int len)
{
    int i = 0;

    if (len % 4 != 0)
    {
        printf("err len\n");
        return -1;
    }

    while (i < len)
    {
        dst[i] = src[i + 3];
        dst[i + 1] = src[i + 2];
        dst[i + 2] = src[i + 1];
        dst[i + 3] = src[i];
        i += 4;
    }

    return 0;
}

//主函数
int main(int argc, char *argv[])
{
    int fd;
    ssize_t ret = 0;
    //打开点表文件
    fd = open("./cjson_list.txt",O_RDONLY);
    if(fd < 0)
    {
        perror("fd open err\n");
        return -1;
    }
    char Point_table[2048];

    ret = read(fd,Point_table,2048);
    if(ret < 0)
    {
        perror("read point table err.");
        return -1;
    }

    //解析点表,创建内核链表
    struct mb_node_list head;
    INIT_LIST_HEAD(&head.list);
    struct mb_node_list mb_node_data_array[5];

    cJSON* root_pt = NULL;
    cJSON* item_pt = NULL;
    cJSON* modbus_pt_ip = NULL;
    cJSON* modbus_pt_port = NULL;
    cJSON* modbus_pt_bedroom_data = NULL;
    cJSON* modbus_pt_bedroom_data_infomation = NULL;
    cJSON* modbus_pt_bedroom_data_key = NULL;
    cJSON* modbus_pt_bedroom_data_name = NULL;
    cJSON* modbus_pt_bedroom_data_addr = NULL;
    cJSON* modbus_pt_bedroom_data_type = NULL;
    root_pt = cJSON_Parse(Point_table);
    item_pt = cJSON_GetObjectItem(root_pt,"mb_dev");
    modbus_pt_ip = cJSON_GetObjectItem(item_pt,"addr");
    modbus_pt_port = cJSON_GetObjectItem(item_pt,"port");

    //将解析到的ip和端口号填充到结构体中
    strcpy(mb_infomation.ip,modbus_pt_ip->valuestring);
    mb_infomation.port = modbus_pt_port->valueint;
    printf("ip:%s\n",mb_infomation.ip);
    printf("port:%d\n",mb_infomation.port);

    //解析modbus点表
    item_pt = cJSON_GetObjectItem(root_pt,"modbus");
    modbus_pt_bedroom_data = cJSON_GetObjectItem(item_pt,"data");
    int array_size = cJSON_GetArraySize(modbus_pt_bedroom_data);
    int k = 0;
    for(k = 0;k<array_size;k++)
    {
        modbus_pt_bedroom_data_infomation = cJSON_GetArrayItem(modbus_pt_bedroom_data,k);
        modbus_pt_bedroom_data_key = cJSON_GetObjectItem(modbus_pt_bedroom_data_infomation,"key");
        modbus_pt_bedroom_data_name = cJSON_GetObjectItem(modbus_pt_bedroom_data_infomation,"name");
        modbus_pt_bedroom_data_addr = cJSON_GetObjectItem(modbus_pt_bedroom_data_infomation,"addr");
        modbus_pt_bedroom_data_type = cJSON_GetObjectItem(modbus_pt_bedroom_data_infomation,"type");
        mb_node_data_array[k].node.key = modbus_pt_bedroom_data_key->valueint;
        mb_node_data_array[k].node.addr = modbus_pt_bedroom_data_addr->valueint;
        mb_node_data_array[k].node.type = modbus_pt_bedroom_data_type->valueint;
        strcpy(mb_node_data_array[k].node.name,modbus_pt_bedroom_data_name->valuestring);
        list_add(&mb_node_data_array[k].list, &head.list);
    }
    struct list_head *pos;
    struct mb_node_list *tmp;
    list_for_each(pos, &head.list)
    {
        tmp = list_entry(pos, struct mb_node_list, list);
        printf("addr = %d, key = %d\n",tmp->node.addr,tmp->node.key);
    }

    /*      创建数据采集线程    */
    pthread_t tid1;
    if (pthread_create(&tid1, NULL, thread1, NULL) != 0)
    {
        perror("pthread_create err.");
    }

    /*      创建指令处理线程    */
    pthread_t tid2;
    if (pthread_create(&tid2, NULL, thread2, NULL) != 0)
    {
        perror("pthread_create err.");
    }

    //回收线程资源
    pthread_join(tid1, NULL);
    pthread_join(tid2, NULL);
}
